﻿using System;
using System.Collections.Generic;
using System.Web.Mvc;
using AutoMapper;
using SapaFinance.DTO;
using SapaFinance.Domain;
using SapaFinance.Domain.Model;
using SapaFinance.GenericRepository;

namespace SapaFinance.Services
{
    public interface ICorporationService
    {
        IAgentService AgentService { get; set; }
        ICfoService CFOService { get; set; }
        void CreateCorporation(CorporationDTO corporationDTO);
        void DeleteCorporation(Guid id);
        void UpdateCorporation(CorporationDTO dto);
        IEnumerable<SelectListItem> GetPayerSelectedListNonCash(Guid id);
        IEnumerable<SelectListItem> GetPayerSelectedListAgentNonCash(Guid id);
        IEnumerable<SelectListItem> GetPayerSelectedListByPaymentType(Guid id);
        IEnumerable<SelectListItem> GetAllCorporationSelectedList(Guid id);
        IEnumerable<CorporationDTO> GetCorporationList();
        Corporation GetCorporation(Guid id);
        void Update(Corporation corporation);
        void DeleteAccount(Guid id);
    }

    public class CorporationService : ICorporationService
    {
        private readonly IGenericRepository<Corporation, Guid> _corporationRepository;
        private readonly IEntityFactory _entityFactory;
        private readonly IMappingEngine _mappingEngine;
        private readonly IUnitOfWork _unitOfWork;

        public CorporationService(IGenericRepository<Corporation, Guid> corporationRepository, IMappingEngine mappingEngine, IUnitOfWork unitOfWork,
                                  IEntityFactory entityFactory)
        {
            _corporationRepository = corporationRepository;
            _mappingEngine = mappingEngine;
            _unitOfWork = unitOfWork;
            _entityFactory = entityFactory;
        }

        public IUserService UserService { get; set; }
        public IPaymentTypeService PaymentTypeService { get; set; }

        #region ICorporationService Members

        public IAgentService AgentService { get; set; }
        public ICfoService CFOService { get; set; }

        public IEnumerable<CorporationDTO> GetCorporationList()
        {
            return _mappingEngine.Map<IEnumerable<Corporation>, IEnumerable<CorporationDTO>>(_corporationRepository.GetAll());
        }

        public void CreateCorporation(CorporationDTO corporationDTO)
        {
            var corporation = _entityFactory.BuildCorporation(corporationDTO);
            var cfos = CFOService.GetCfoList(corporationDTO.CheckedCfo);
            corporation.Visible(cfos);
            _corporationRepository.Insert(corporation);
            _unitOfWork.Flush();
        }

        public void DeleteCorporation(Guid id)
        {
            var entity = _corporationRepository.GetById(id);
            _corporationRepository.Delete(entity);
            _unitOfWork.Flush();
        }

        public void DeleteAccount(Guid id)
        {
            var corporation = _corporationRepository.Specify<ICorporationSpecification>().WithAccount(id).ToResult().Single();
            var account = corporation.GetAccount(id);
            corporation.DeleteAccount(account);
            _unitOfWork.Update(corporation);
            _unitOfWork.Flush();
        }

        public void UpdateCorporation(CorporationDTO dto)
        {
            var agent = AgentService.GetAgent(dto.SelectedAgent);
            var corporation = _corporationRepository.GetById(dto.UID);
            corporation.FullName = dto.FullName;
            corporation.Name = dto.Name;
            corporation.SetAgent(agent);
            corporation.LegalAddress = dto.LegalAddress;
            corporation.Tin = dto.Tin;
            corporation.Kpp = dto.Kpp;
            corporation.Okonh = dto.Okonh;
            corporation.Okpo = dto.Okpo;
            corporation.IsPayer = dto.IsPayer;
            corporation.AccountantName = dto.AccountantName;
            corporation.DirectorName = dto.DirectorName;
            corporation.ActualAddress = dto.ActualAddress;
            corporation.Description = dto.Description;
            corporation.RegistrationDate = dto.RegistrationDate;
            corporation.IsHidden = dto.IsHidden;
            corporation.Change(UserService.GetUser(dto.CurrentUser));
            corporation.Visible(CFOService.GetCfoList(dto.CheckedCfo));
            Update(corporation);
        }

        public Corporation GetCorporation(Guid id)
        {
            return _corporationRepository.GetById(id);
        }

        public void Update(Corporation corporation)
        {
            _corporationRepository.Update(corporation);
            _unitOfWork.Flush();
        }

     
        public IEnumerable<SelectListItem> GetPayerSelectedListNonCash(Guid id)
        {
            var corporations = _corporationRepository.Specify<ICorporationSpecification>().Our().IsPayer().ToResult().ToList();
            return GetCorporationSelectedList(id, corporations,false);
        }

        public IEnumerable<SelectListItem> GetPayerSelectedListByPaymentType(Guid id)
        {
            var payerListStrategy = PaymentTypeService.GetPayerListByPaymentTypeStrategy(id);
            return payerListStrategy.GetPayerList(this);
        }

        public IEnumerable<SelectListItem> GetAllCorporationSelectedList(Guid id)
        {
            var corporations = _corporationRepository.GetAll();
            return GetCorporationSelectedList(id, corporations, true);
        }


        public IEnumerable<SelectListItem> GetPayerSelectedListAgentNonCash(Guid id)
        {
            var corporations = _corporationRepository.Specify<ICorporationSpecification>().IsPayer().NoOur().ToResult().ToList();
            return GetCorporationSelectedList(id, corporations,true);
        }

        #endregion

        private IEnumerable<SelectListItem> GetCorporationSelectedList(Guid id, IEnumerable<Corporation> corporations, bool empty)
        {
            var result = new List<SelectListItem>{};
            if(empty) result.Add(_entityFactory.BuildEmptyItem());
            result.AddRange(_mappingEngine.Map<IEnumerable<Corporation>, IEnumerable<SelectListItem>>(corporations));
            return Guid.Empty.Equals(id)
                       ? result
                       : _mappingEngine.Map<Corporation, IEnumerable<SelectListItem>>(_corporationRepository.GetById(id));
        }
    }
}